//****************************************************
// Porman Project 2
// Filename: CRenderDevice.h
// Date: 2007/10/06
// Author: KengYu Lin
// Modify:
//****************************************************
#ifndef _CRENDERDEVICE_H
#define _CRENDERDEVICE_H

#include <list>
#include "CDeviceCreator.h"
#include "CGLDef.h"
#include "CStateObject.h"
#include "CBaseObject.h"
#include "CVertexDeclObject.h"
#include "CShaderObject.h"
#include "CFXObject.h"
#include "CTextureObject.h"
#include "CBufferObject.h"
#include "CDepthStencilObject.h"
#include "CFramebufferObject.h"
#include "COcclusionQueryObject.h"
#include "CWordSystem.h"
#include "CAssert.h"

namespace Porman
{

namespace GL
{

//----------------------------
// Class CGL:
//----------------------------
class CRenderDevice
{
    friend class CDeviceCreator;
    friend class CShaderObject;
    friend class CFXObject;
public:
    struct SRenderingInfoPerFrame 
    {
    public:
        SRenderingInfoPerFrame( void ) { reset(); }

        void reset( void )
        {
            m_iNumOfBatches = 0;
            m_iNumOfPointPrimitives = 0;
            m_iNumOfLineStripPrimitives = 0;
            m_iNumOfLineLoopPrimitives = 0;
            m_iNumOfLinePrimitives = 0;
            m_iNumOfTriangleStripPrimitives = 0;
            m_iNumOfTriangleFanPrimitives = 0;
            m_iNumOfTrianglePrimitives = 0;
        }

        void operator= ( const SRenderingInfoPerFrame& l )
        {
            m_iNumOfBatches = l.m_iNumOfBatches;
            m_iNumOfPointPrimitives = l.m_iNumOfPointPrimitives;
            m_iNumOfLineStripPrimitives = l.m_iNumOfLineStripPrimitives;
            m_iNumOfLineLoopPrimitives = l.m_iNumOfLineLoopPrimitives;
            m_iNumOfLinePrimitives = l.m_iNumOfLinePrimitives;
            m_iNumOfTriangleStripPrimitives = l.m_iNumOfTriangleStripPrimitives;
            m_iNumOfTriangleFanPrimitives = l.m_iNumOfTriangleFanPrimitives;
            m_iNumOfTrianglePrimitives = l.m_iNumOfTrianglePrimitives;
        }
             
        int m_iNumOfBatches;
        int m_iNumOfPointPrimitives;
        int m_iNumOfLineStripPrimitives;
        int m_iNumOfLineLoopPrimitives;
        int m_iNumOfLinePrimitives;
        int m_iNumOfTriangleStripPrimitives;
        int m_iNumOfTriangleFanPrimitives;
        int m_iNumOfTrianglePrimitives;
    };

public:
    //-------------------------
    // Vertex Elements:
    //-------------------------
    PGL_API CBufferObject* createBufferObject( EBufferTarget enumTarget, int iSizeInByte, EBufferUsage enumUsage, ERESULT* pError = NULL );
    PGL_API ERESULT destroyBufferObject( CBufferObject** ppBufferObj );
    PGL_API ERESULT bindStreamSource( CBufferObject* pBufferObj, int iStride );
    PGL_API ERESULT bindIndexBuffer( CBufferObject* pBufferObj, EIndexBufferType enumType );

    PGL_API CVertexDeclObject* createVertexDeclObject( SVertexElement* pVertexElementsArray, ERESULT* pError = NULL );
    PGL_API CVertexDeclObject* createVertexDeclObject( CVertexElementArray* pVertexElementsArray, ERESULT* pError = NULL );
    PGL_API ERESULT destroyVertexDeclObject( CVertexDeclObject** ppVertexDeclObj );
    PGL_API ERESULT bindVertexDeclObject( CVertexDeclObject* pVertexDeclObj );

    //----------------------------------
    // Shader Functions:
    //----------------------------------
    PGL_API CShaderObject* createShaderObjectFromText( EShaderType enumType, const char* sText, const char* sEntryFunction, 
                                                       const char** sCompileArgs, std::string* pMsg = NULL, ERESULT* pError = NULL );

    PGL_API CShaderObject* createShaderObjectFromFile( EShaderType enumType, const char* sFileName, const char* sEntryFunction, 
                                                       const char** sCompileArgs, std::string* pMsg = NULL, ERESULT* pError = NULL );

    PGL_API CShaderObject* createShaderObjectFromObj( EShaderType enumType, const char* sObj, const char* sEntryFunction, 
                                                      const char** sCompileArgs, std::string* pMsg = NULL, ERESULT* pError = NULL );

    PGL_API ERESULT destroyShaderObject( CShaderObject** ppShaderObj );
    PGL_API ERESULT compileShader( CShaderObject* pShaderObj, bool bForce, std::string* pMsg = NULL );
    PGL_API ERESULT bindVertexShaderObject( CShaderObject* pVertexShaderObj );
    //PGL_API ERESULT bindGeometryShaderObject( CShaderObject* pGeometryShaderObj );
    PGL_API ERESULT bindPixelShaderObject( CShaderObject* pPixelShaderObj );

    //----------------------------------
    // FX Functions:
    //----------------------------------
    PGL_API CFXObject* createFXObjectFromText( const char* sText, const char** sCompileArgs, std::string* pMsg = NULL, ERESULT* pError = NULL );
    PGL_API CFXObject* createFXObjectFromFile( const char* sFileName, const char** sCompileArgs, std::string* pMsg = NULL, ERESULT* pError = NULL );
    PGL_API ERESULT destoryFXObject( CFXObject** ppFXObj );
    PGL_API ERESULT bindFXObjectPass( CFXObject::CTechnique::CPass* pPass, bool bRestoreState );
    PGL_API ERESULT unbindFXObjectPass( void );

    //----------------------------------
    // Texture Functions:
    //----------------------------------
    PGL_API CTexture2DObject* createTexture2DObject( CTexture2DObject::STexture2DDesc& Desc, ERESULT* pError = NULL );
    PGL_API CTexture3DObject* createTexture3DObject( CTexture3DObject::STexture3DDesc& Desc, ERESULT* pError = NULL );
    PGL_API CTextureCubeObject* createTextureCubeObject( CTextureCubeObject::STextureCubeDesc& Desc, ERESULT* pError = NULL );
    PGL_API ERESULT destroyTextureObject( CTexture2DObject** ppTextureObj );
    PGL_API ERESULT destroyTextureObject( CTexture3DObject** ppTextureObj );
    PGL_API ERESULT destroyTextureObject( CTextureCubeObject** ppTextureObj );

    PGL_API CDepthStencilObject* createDepthStencilObject( ERESULT* pError = NULL );
    PGL_API ERESULT destroyDepthStencilObject( CDepthStencilObject** ppDepthStencilObj );

    //----------------------------------
    // Framebuffer Functions:
    //----------------------------------
    PGL_API CFramebufferObject* createFramebufferObject( ERESULT* pError = NULL );
    PGL_API ERESULT destroyFramebufferObject( CFramebufferObject** ppFramebufferObj );
    PGL_API ERESULT bindFramebuffer( CFramebufferObject* pFramebufferObj );

    //----------------------------------
    // Occlusion Query:
    //----------------------------------
    PGL_API COcclusionQueryObject* createQueryObject( ERESULT* pError = NULL );
    PGL_API ERESULT destroyQueryObject( COcclusionQueryObject** ppQueryObj );

    //----------------------------------
    // Draw Functions:
    //----------------------------------
    PGL_API ERESULT drawTexts( const char* pString, int iX, int iY, float fScale, float fColor[4] );
    PGL_API ERESULT drawPrimitive( EPrimitiveType enumType, int iStartVertex, int iPrimitiveCount );
    PGL_API ERESULT drawIndexPrimitive( EPrimitiveType enumType, int iNumVertex, int iStartIndex, int iPrimitiveCount );

    //------------------------
    // StateObject Functions:
    //------------------------
    PGL_API ERESULT bindScissorStateObject( const CScissorStateObject& scissor );
    PGL_API ERESULT bindAlphaStateObject( const CAlphaStateObject& alpha );
    PGL_API ERESULT bindBlendStateObject( const CBlendStateObject& blend );
    PGL_API ERESULT bindDepthStateObject( const CDepthStateObject& depth );
    PGL_API ERESULT bindStencilStateObject( const CStencilStateObject& stencil );
    PGL_API ERESULT bindCullFaceStateObject( const CCullFaceStateObject& cullface );
    PGL_API ERESULT bindPolygonOffsetStateObject( const CPolygonOffsetStateObject& polygonoffset );
    PGL_API ERESULT bindPolygonModeStateObject( const CPolygonModeStateObject& polygonmode );

    PGL_API const CScissorStateObject&       getScissorStateObject( void );
    PGL_API const CAlphaStateObject&         getAlphaStateObject( void );
    PGL_API const CBlendStateObject&         getBlendStateObject( void );
    PGL_API const CDepthStateObject&         getDepthStateObject( void );
    PGL_API const CStencilStateObject&       getStencilStateObject( void );
    PGL_API const CCullFaceStateObject&      getCullFaceStateObject( void );
    PGL_API const CPolygonOffsetStateObject& getPolygonOffsetStateObject( void );
    PGL_API const CPolygonModeStateObject&   getPolygonModeStateObject( void );

    PGL_API ERESULT setVsync( int iInterval );
    PGL_API int getVsync( void );
    PGL_API ERESULT setPointSize( float fSize );
    PGL_API float getPointSize( void );
    PGL_API ERESULT setLineWidth( float fWidth );
    PGL_API float getLineWidth( void );

    //------------------------
    // Frame Buffer Functions:
    //------------------------
    PGL_API ERESULT swapBuffer( bool bFlush = false, SRenderingInfoPerFrame* pRenderingInfoPerFrame = NULL );
    PGL_API ERESULT swapBuffer( CRenderCanvas* pCanvas, bool bFlush = false, SRenderingInfoPerFrame* pRenderingInfoPerFrame = NULL );
    PGL_API ERESULT clearBuffer( bool bClearColorbuffer, bool bClearDepthBuffer, bool bClearStencilBuffer );

    PGL_API ERESULT setColorBuffer( float fRed, float fGreen, float fBlue, float fAlpha );
    PGL_API ERESULT setColorBuffer( float fColor[4] );
    PGL_API ERESULT setDepthBuffer( float fDepth );
    PGL_API ERESULT setStencilBuffer( int iStencil );

    PGL_API ERESULT setColorBufferMask( bool bRed = true, bool bGreen = true, bool bBlue = true, bool bAlpha = true );
    PGL_API ERESULT setDepthBufferMask( bool bDepth = true );
    PGL_API ERESULT setStencilBufferMask( EFaceType enumFace, unsigned int uiMask );

    //-----------------------
    // Statistic Resource:
    //-----------------------
    PGL_API int getNumOfShaderObject( void );
    PGL_API int getNumOfFXObject( void );
    PGL_API int getNumOfBufferObject( void );
    PGL_API int getNumOfTextureObject( void );
    PGL_API int getNumOfFrameBufferObject( void );
    PGL_API int getNumOfDepthStencilObject( void );
    PGL_API int getNumOfVertexDevlObject( void );
    PGL_API const unsigned char* getGraphicsCardVendor( void );

    //-------------------
    // Others:
    //-------------------
    PGL_API bool switchRenderCanvas( const CRenderCanvas* pCanvas );
    PGL_API ERESULT setViewport( int iX, int iY, int iWidth, int iHeight, float fMinZ, float fMaxZ );
    PGL_API DWORD getCurThreadID( void );
    PGL_API bool beginThread( void );
    PGL_API bool endThread( void );

protected:
    struct SViewport
    {
    public:
        SViewport( void ) { reset(); }
        void reset( void ) { iX = 0; iY = 0; iWidth = 800; iHeight = 600; fMinZ = 0.0f; fMaxZ = 1.0f; }

    public:
        int iX, iY;
        int iWidth, iHeight;
        float fMinZ, fMaxZ;
    };

    struct SRenderStatesCallbacks
    {
    public:
        static CGbool set( CGstateassignment sa );
        static CGbool reset( CGstateassignment sa );
        static CGbool validate( CGstateassignment sa );

    protected:
        static CGbool _checkingState( CGstateassignment& sa );

    public:
        static CRenderDevice* pRenderDevice;
    };

    struct SRenderStates
    {
    public:
        SRenderStates( void ) { reset(); }
        void reset( void );

    public:
        float m_fPointSize;
        float m_fLineWidth;
        float m_fClearColor[4];
        float m_fClearDepth;
        int   m_iClearStencil;
        int   m_iVSyncInterval;
        
        bool m_bColorWrite[4];
        bool m_bDepthWrtie;
        unsigned int m_uiStencilMask;

        CAlphaStateObject         m_AlphaStateObj;
        CBlendStateObject         m_BlendStateObj;
        CDepthStateObject         m_DepthStateObj;
        CStencilStateObject       m_StencilStateObj;
        CScissorStateObject       m_ScissorStateObj;
        CCullFaceStateObject      m_CullFaceStateObj;
        CPolygonOffsetStateObject m_PolygonOffsetStateObj;
        CPolygonModeStateObject   m_PolygonModeStateObj;

        //--------------------------
        // Shader Objects:
        //--------------------------
        CShaderObject*      m_pCurBindVertexShaderObj;
        CShaderObject*      m_pCurBindGeometryShaderObj;
        CShaderObject*      m_pCurBindPixelShaderObj;

        //--------------------------
        // FX Objects:
        //--------------------------
        CFXObject::CTechnique::CPass* m_pCurBindPassObj;
        bool m_bFXResotreState;

        //--------------------------
        // Buffer Objects:
        //--------------------------
        CVertexDeclObject*  m_pCurVertexDeclObj;
        CBufferObject*      m_pCurStreamBufferObj;
        CBufferObject*      m_pCurIndexBufferObj;
        EIndexBufferType    m_eCurIndexBufferType;

        int                 m_iCurVertexStride;
        unsigned int        m_uiCurFrameBufferID;

        CBufferObject*      m_pWordBufferObj;
        CBufferObject*      m_pWordIndexBufferObj;

        //--------------------------
        // Others:
        //--------------------------
        SViewport m_CurViewportData;
        bool m_bIsVertexDeclDirty;
        bool m_bIsVertexStrideDirty;
        bool m_bIsVertexShaderDirty;
    };

protected:
    CRenderDevice( void );
    virtual ~CRenderDevice( void );
    
    ERESULT _initial( const CRenderCanvas* pSurface );
    void _uninitial( void );
    bool _initialCg( void );
    void _addObjIntoTable( CBaseObject* pObj );
    void _deleteObjFromTable( const CBaseObject* pObj );

    CGcontext* _getShaderContext( void ) { return &m_CgContext; }
    CGprofile* _getVsProfile( void )     { return &m_CgVertexProfile; }
    CGprofile* _getGsProfile( void )     { return &m_CgGeometryProfile; }
    CGprofile* _getPsProfile( void )     { return &m_CgPixelProfile; }

    inline bool _setSurface( const CRenderCanvas* pSurface );
    inline void _drawPrimitive( EPrimitiveType enumType, int iStartVertex, int iPrimitiveCount );
    inline void _drawIndexPrimitive( EPrimitiveType enumType, int iNumVertex, int iStartIndex, int iPrimitiveCount );

    inline bool _beginDrawing( void );
    inline void _endDrawing( EPrimitiveType enumType, int iPrimitiveCount );

protected:
    //--------------------------
    // Cg:
    //--------------------------
    CGcontext           m_CgContext;
    CGprofile           m_CgVertexProfile;
    CGprofile           m_CgGeometryProfile;
    CGprofile           m_CgPixelProfile;

    //--------------------------
    // Render states:
    //--------------------------
    SRenderStates       m_RenderStates;

    //--------------------------
    // Others:
    //--------------------------
    HDC                     m_hDC;
    HGLRC                   m_hRC;
    DWORD                   m_hThreadID;
    bool                    m_bBeginThread;
    int                     m_iPixelFormat;
    CWordSystem             m_WordSys;
    std::list<CBaseObject*> m_listObjTable;
    SRenderingInfoPerFrame  m_RenderingInfoPerFrame;
    float                   m_fVBString[2048];
    unsigned short          m_usIBString[2048];
};  

}//End namespace GL

}//End namespace Porman

#endif